﻿using HQHS.Library.Common.Threading;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace HQHS.Library.Common.Colloection
{
    public class MissingValueDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        // Fields
        public delegate bool MissingValueTryGetDelegate(TKey key, ref TValue value);
        private ReaderWriterLockSlim _dicLock;
        private KeyedReaderWriterLockSlim<TKey> _keyLock;
        private List<TKey> _missingKeys;
        protected MissingValueTryGetDelegate _missingValueTryGet;

        // Methods
        public MissingValueDictionary(MissingValueTryGetDelegate missingValueTryGet)
            : this(missingValueTryGet, EqualityComparer<TKey>.Default)
        {
        }

        public MissingValueDictionary(MissingValueTryGetDelegate missingValueTryGet, IEqualityComparer<TKey> comparer)
            : base(comparer)
        {
            this._missingKeys = new List<TKey>();
            this._dicLock = new ReaderWriterLockSlim();
            this._keyLock = new KeyedReaderWriterLockSlim<TKey>();
            this._missingValueTryGet = missingValueTryGet;
        }

        public bool TryGetValue(TKey key, ref TValue value)
        {
            bool flag;
            this._dicLock.EnterReadLock();
            try
            {
                flag = base.TryGetValue(key, out value);
            }
            finally
            {
                this._dicLock.ExitReadLock();
            }
            if (!flag && !this._missingKeys.Contains(key))
            {
                this._keyLock.EnterWriteLock(key);
                try
                {
                    if (!this._missingKeys.Contains(key))
                    {
                        flag = this._missingValueTryGet(key, ref value);
                        if (!flag)
                        {
                            this._missingKeys.Add(key);
                        }
                        this._dicLock.EnterWriteLock();
                        try
                        {
                            this[key] = value;
                        }
                        finally
                        {
                            this._dicLock.ExitWriteLock();
                        }
                    }
                }
                finally
                {
                    this._keyLock.ExitWriteLock(key);
                }
            }
            if (((TValue)value) == null)
            {
                flag = false;
            }
            return flag;
        }

        // Properties
        protected ReaderWriterLockSlim DictionaryUpdateLock
        {
            get
            {
                return this._dicLock;
            }
        }

        public virtual TValue this[TKey key]
        {
            get
            {
                TValue local2 = default(TValue);
                if (!this.TryGetValue(key, ref local2))
                {
                }
                return local2;
            }
            set
            {
                lock (this)
                {
                    base[key] = value;
                }
            }
        }

        protected KeyedReaderWriterLockSlim<TKey> KeyLoadLock
        {
            get
            {
                return this._keyLock;
            }
        }
    }
}
